# -*- coding: utf-8 -*-
import os
KEYWORD_LIST_FUNC=['if','while','for','switch']
g_allFuncList=[]
g_includeList=[]
class lexer_c_getfunc:
    def __init__(self, fileFullName):
        self.current_row = -1
        self.current_line = 0
        self.fullName=fileFullName
        if   not os.path.exists(fileFullName):
            return None     #文件名为空  或者 文件不存在         
        try:            
            fin = open(self.fullName, "r",  encoding='utf-8', errors="ignore")
            input_file = fin.read()
            fin.close()
        except:
            fin.close()      
            return None     #打开文件失败   
        self.input_str = input_file.splitlines(False)  
        self.max_line = len(self.input_str) - 1
    def getchar(self):  #   从整个文档中取出一个 char
        self.current_row += 1
        if self.current_row == len(self.input_str[self.current_line]):
            self.current_line += 1
            self.current_row = 0
            while True:
                if len(self.input_str[self.current_line])!=0:
                    break                
                self.current_line+=1
                if self.current_line == self.max_line:
                    return 'SCANEOF'
        if self.current_line == self.max_line:
            return 'SCANEOF'
        return self.input_str[self.current_line][self.current_row]
    def  ungetchar(self):   #往文档存回一个 char
        self.current_row = self.current_row - 1
        if self.current_row < 0:
            self.current_line = self.current_line - 1
            self.current_row = len(self.input_str[self.current_line]) - 1
        return self.input_str[self.current_line][self.current_row]
    def getIncludeFile(self, linestr):
        start=0
        end=0
        for i in range(7, len(linestr)):
            if start !=0 and linestr[i] == '>':
                end = i
                return linestr[start: end]
            elif start ==0 and linestr[i] == '<':
                start = i+1
        return None 
    def getFunctionNameInLine(self, strline):
        for i in range(0, len(strline)):
            if strline[i] == '(':
                break
        else:   
            return None
        j=i-1
        for i in range( j,-1,  -1):
            if ord(strline[i]) > 127:   #非 ASCII 码 
                return None
            if strline[i].isalnum() == False and strline[i] !='_':  #   含有非函数名字符则停止
                str1=strline[i+1: j+1]          
                if str1 in KEYWORD_LIST_FUNC:   # 不是关键字
                    break
                else:                                       #函数名
                    return str1
        return None
    
    def scanFunction(self):
        global g_allFuncList
        global g_includeList
        if self.current_line == self.max_line:
            return ('SCANEOF', self.max_line)
        
        str1 = self.input_str[self.current_line].strip()
        if len(str1)==0 :     # 空行      
            self.current_line += 1
            self.current_row = -1
            return None
        if str1[:2] =='#i' :#包含文件名
            str2 = self.getIncludeFile(str1)
            if str2 != None:
                if str2 not in g_includeList:
                    g_includeList.append(str2)
            self.current_line += 1
            self.current_row = -1
            return None
        if '(' not in str1:   # 没有 左括号
            self.current_line += 1
            self.current_row = -1
            return None
        #本行出现(,记录行号
        lineOfLeft =self.current_line
        while(True):
            #查找‘)’  -->  { 
            current_char = self.getchar()
            if current_char == ')':#后面可能有注释 /**/  或者  //    跳过   ;还有=跳过
                while(True):
                    current_char = self.getchar()
                    if current_char == '{':#当前行中包含函数名，记录行号和获取函数名
                        str1 =self.getFunctionNameInLine(self.input_str[lineOfLeft])
                        if str1:
                            g_allFuncList.append(str1)
                            return (str1, lineOfLeft)
                        return None
                    elif current_char == '(':
                        lineOfLeft =self.current_line
                        continue
                    elif current_char == ';' or current_char == '=':#分号表示此处为函数调用，并非函数体跳过  =可能是函数指针数组
                        self.current_line += 1
                        self.current_row = -1
                        return None
                    elif current_char == '/':
                        next_char = self.getchar()
                        if next_char == '/':  #  单行注释跳过当前行，下面已经是下一行      
                            self.current_line += 1
                            self.current_row = -1
                            next_char = self.getchar()#换行的第一个是 ｛ 认为是函数所在行                                
                            if next_char == '{':  #  行首是 { ,将字符存回去 ，回到当前的while开始处
                                self.ungetchar()
                                continue
                            elif next_char == 'SCANEOF':
                                return ('SCANEOF', 0)
                            else:
                                return None
                        elif current_char == '*':  # 块注释  /**/
                            next_char = self.getchar()
                            while True:
                                if next_char == '*':
                                    end_char = self.getchar()
                                    if end_char == '/':
                                        break
                                    if end_char == 'SCANEOF':
                                        return ('SCANEOF', 0)
                                elif next_char == 'SCANEOF':
                                    return ('SCANEOF', 0)
                                next_char = self.getchar()
            elif  current_char == 'SCANEOF':
                return ('SCANEOF', 0)
    def lexer_analysis(self):        
        [dirname,filename]=os.path.split(self.fullName)
        funcDict={} #本字典 属于 子自典，key = 函数名,value = 行号
        # 分析c文件，一直到文档结束
        while True:
            r = self.scanFunction()
            if r is not None:
                if r[0] == 'SCANEOF':       # 文档结尾，结束查找
                    break
                funcDict.setdefault(r[0], r[1])     #查找到函数名，记录所在行号
        return (filename, funcDict)
'''        
{   'test.c': {'TempADC': 4, 'DoNothing': 19, 'DoNothing1': 22}, 
    '11test.c': {'LcdTest': 12, 'UartTest': 63, 'TempADC': 74, 'PWMTest': 100}}
'''
